package com.ce.framework.auth;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;


import com.ce.framework.context.FrameworkContext;
import com.ce.framework.util.LogUtil;
import com.ce.framework.util.StringUtil;
import com.ce.sys.login.model.User;
import com.ce.util.DbUtil;
import com.ce.util.RegeditUtil;
import com.ce.util.SessionUtil;


/**
 * 嫦娥软件有限公司 版权所有 2013
 * 创建人： andy 
 * 创建时间： 2013-10-2 上午10:55:22
 * 功能描述：  登录验证过滤器
 * ==================================
 * 修改历史
 * 修改人        修改时间      修改位置（函数名）
 *
 * ==================================
 */
public class CheckLoginFilter implements Filter
{
	public static String path;
	
	static Logger logger = Logger.getLogger("OPEN_URL");
	
	private static long lastUpdate;//上次更新数据库中SESSION_DATE的时间，值取自System.currentTimeMillis()

	private static long updateInteval = 60*60*1000;//更新数据库中SESSION_DATE的时间的频率，单位为毫秒
	
	private List<String> excludeStr = new ArrayList<String>();
	private List<Pattern> excludePat = new ArrayList<Pattern>();
	
    public void init(FilterConfig arg0) throws ServletException {
    	String urls = arg0.getInitParameter("exclude");
    	if(urls!=null && urls.length()>0){//将排除URL解析并放到相应的列表中
    		String[] ary = urls.split("\\s*,\\s*");
    		for(String str:ary){
    			if(str.length()==0){
    				continue;
    			}
    			if(str.startsWith("REG:")){//正则表达式
    				excludePat.add(Pattern.compile(str.substring("REG:".length())));
    			}
    			else{//一般匹配
    				excludeStr.add(str);
    			}
    		}
    	}
    	//清除一天之前的SESSION数据
	    DbUtil.executeSqlUpdate("delete SYS_T_SESSION$INF where ADD_DATE<sysdate-1");
    }

    public void doFilter(ServletRequest arg0, 
            ServletResponse arg1, 
            FilterChain arg2) 
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest)arg0;
        HttpServletResponse response = (HttpServletResponse) arg1;
        String res = ""+RegeditUtil.getRegeditBoolValue("SYSTEM_SHOW_LOAD_TIME");
        if("true".equals(res)){
            request.setAttribute("request-start", System.currentTimeMillis());//在request中记录下开始请求的时间，用于计算服务器加载时间
        }
        if(!res.equals(getCookie(request, "showLoadTime"))){//写入到cookie，使用easyui框架时也能从cookie中获取
        	setCookie(response, "showLoadTime", res, 999, "/");
        }
        String pagePath = getPagePath(request); 
        logger.info(request.getRequestURL()+(request.getQueryString()!=null?"?"+request.getQueryString():""));
        User user = User.getUser(request);
        if(path==null){
        	path = request.getContextPath();
        	FrameworkContext.path = path;
        }
        initSessionId(request, response);
        if(user==null){
        	user = User.getUser(request);
        }
    	if(user==null){
            if(isExclude(request.getRequestURI())){//如果在排除URL范围内，则不进行转向
                arg2.doFilter(arg0,arg1);
            	return;
            }
    		request.setAttribute("turnToPage",request.getContextPath()+"/login/Login_reLogin.action");
    		request.getSession().setAttribute("loginToPage", pagePath);
    		if(request.getParameter("login")!=null){//如果带此参数，则直接跳转到登录界面
    			String loginPage = RegeditUtil.getRegeditStringValue("LOGIN_PAGE");
    			if(StringUtil.isNotBlank(loginPage)){
    				response.getWriter().write("<script>location.href='"+loginPage+"';</script>");
    				return;
    			}
    		}
    		response.sendRedirect(request.getContextPath()+"/common/noSessionPage.jsp");  //返回重新登录界面
            return;
    	}
        arg2.doFilter(arg0,arg1);
    }
    
    private boolean isExclude(String uri){
    	for(String str:excludeStr){
    		if(str.equals(uri)){
    			return true;
    		}
    	}
    	for(Pattern pat:excludePat){
    		if(pat.matcher(uri).matches()){
    			return true;
    		}
    	}
    	return false;
    }
    
    public static void initSessionId(HttpServletRequest request,HttpServletResponse response) {
        String ssoid = getSsoid(request);
        User user = User.getUser(request);
        //如果COOKIE中的SSO_ID与SESSION中的SSO_ID不一致，说明用户退出后又重新登录了，此时清空SESSION
        String sessoid = (String) request.getSession().getAttribute("SSO_ID");
        if(ssoid!=null&&sessoid!=null&&user!=null&&!ssoid.equals(sessoid)){
			System.out.println(path+"\tSESSION_REMOVED:"+request.getSession().getAttribute("SSO_ID"));
        	SessionUtil.removeSession(request.getSession());
        	user = null;
        }
        if(user == null && ssoid!=null){
			System.out.println(path+"\tSSO_ID:"+ssoid);
			String usrId = DbUtil.getFirstStringSqlQuery("select SESSION_VALUE from SYS_T_SESSION$INF where SESSION_ID=? and add_date>sysdate-1",
					new Object[]{ssoid});
			if(usrId==null){//如果从本地库中未找到用户登录信息，则从远程库中查找
				String checkUrl = RegeditUtil.getRegeditStringValue("SYSTEM_REMOTE_CHECK_URL");
				if(StringUtil.isNotBlank(checkUrl)){
					try {
						usrId = NetUtil.getContent(checkUrl+"?ssoid="+ssoid);
					} catch (Exception e) {
						LogUtil.logError(e);
					}
					if(StringUtil.isNotBlank(usrId)){//如果从远程查询到用户ID,则记录到本地库中
						if(!"super".equals(usrId) && DbUtil.getFirstIntSqlQuery("select count(*) from sys_t_person where vc_del$flag=0 and vc_id=?",new Object[]{usrId})==0){
							try {
								String logname = NetUtil.getContent(checkUrl+"?type=logname&ssoid="+ssoid);
								usrId = DbUtil.getFirstStringSqlQuery("select vc_id from sys_t_person where vc_log$name=? and vc_del$flag=0",new Object[]{logname});
								if(StringUtil.isBlank(usrId)){
									usrId = DbUtil.getFirstStringSqlQuery("select vc_id from sys_t_person where vc_name=? and vc_del$flag=0",new Object[]{logname});
								}
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
					    String sql = "insert into SYS_T_SESSION$INF(SESSION_ID,SESSION_VALUE) values(?,?)";
						DbUtil.executeSqlUpdate(sql ,new Object[]{ssoid,usrId});
					}
				}
			}
			if(StringUtil.isNotBlank(usrId)){
				DbUtil.executeSqlUpdate("update SYS_T_SESSION$INF set add_date=sysdate where SESSION_ID=?" ,new Object[]{ssoid});
    			user = SessionUtil.initSessionUser(usrId, request, response);
    			request.getSession().setAttribute("SSO_ID", ssoid);
			}
        }
    	if(System.currentTimeMillis()-lastUpdate>updateInteval){//每隔一小时，更新一次数据库的SESSION日期，防止用户未退出登录，但其它WAR包提示未登录的情况
    		lastUpdate = System.currentTimeMillis();
			DbUtil.executeSqlUpdate("update SYS_T_SESSION$INF set add_date=sysdate where SESSION_ID=?" ,new Object[]{ssoid});
    	}
	}

	private static String getSsoid(HttpServletRequest request){
    	if(request.getCookies()!=null){
        	for(Cookie c:request.getCookies()){
        		if("SSO_ID".equals(c.getName())){//使用COOKIE中的UUID登录
        			return c.getValue();
        		}
        	}
    	}
    	return request.getParameter("SSO_ID");
    }

    private String getPagePath(HttpServletRequest request) {
		StringBuffer buff = new StringBuffer(request.getRequestURL().toString());
		@SuppressWarnings("unchecked")
		Enumeration<String> en = request.getParameterNames();
		String pname = null,pvalue = null;
		while(en.hasMoreElements()){
			pname = en.nextElement();
			pvalue = request.getParameter(pname);
			buff.append(pvalue.indexOf("?")>0?"&":"?").append(pname).append("=").append(pvalue);
		}
		return buff.toString();
	}

	/**
	 * 写COOKIE值
	 * @param name		名称
	 * @param value		COOKIE值
	 * @param expire	有效期，单位为天
	 * @param path		绑定路径
	 */
	protected void setCookie(HttpServletResponse response,String name,String value,int expire,String path){
		try {
			value = URLEncoder.encode(value,"UTF-8");
		} catch (UnsupportedEncodingException e) {
		}
		Cookie c = new Cookie(name,value);
		c.setPath(path);
		c.setMaxAge(expire*24*60*60);
		response.addCookie(c);
	}

	/**
	 * 读取COOKIE的值
	 * @param name
	 * @return
	 */
	protected String getCookie(HttpServletRequest request,String name){
		if(request==null||name==null||request.getCookies()==null){
			return null;
		}
		for(Cookie c:request.getCookies()){
			if(name.equals(c.getName())){
				try {
					return URLDecoder.decode(c.getValue(),"UTF-8");
				} catch (UnsupportedEncodingException e) {
					return c.getValue();
				}
			}
		}
		return null;
	}
	
	public void destroy() {
        
        
    }

}
